#include "solver.h"

void Solver::solver(int trace_size, vector<int>& selected_traces) {
        int i, j;
        IloEnv env;
        time_t start,end;
        
        //define variables.........................
        //assert(mode_num == 1);
        IloModel model(env);
        
        /*define decision variables*/
        //define Zj
        IloNumVarArray Zjk(env, mode_num * tot_DFF_num, 0, 1, ILOINT);
        IloNumVarArray Xi(env, tot_DFF_num, 0, 1, ILOINT);
        //define Xij, i is list id, j is list content 
        NumVarMatrix yijk(env, mode_num * tot_DFF_num);
        for (i = 0; i < mode_num * tot_DFF_num; i++) 
                yijk[i] = IloNumVarArray(env, tot_DFF_num, 0, 1, ILOINT);
        
        try{
                set<int>::iterator it_set;
                set<int>::iterator it_set1;
                vector<TresMap*>::iterator it_map;
                map<int, set<int> > myMap1;
                map<int, set<int> >::iterator it_M;
                
                //constraint 1, yij <= Xi
                for (i = 0; i < mode_num; i++) {
                        myMap1.clear();
                        for(it_map = Mymap[i].begin(); it_map != Mymap[i].end(); it_map++)
                        {
                                for(it_set = (*it_map)->R0_seq.begin(); it_set != (*it_map)->R0_seq.end(); it_set++){
                                        myMap1[*it_set].insert((*it_map)->DFF_id);
                                        (*it_map)->Overlap.insert(*it_set);
                                }
                        
                                for(it_set = (*it_map)->R1_seq.begin(); it_set != (*it_map)->R1_seq.end(); it_set++){
                                        myMap1[*it_set].insert((*it_map)->DFF_id);
                                        (*it_map)->Overlap.insert(*it_set);
                                }
                        
                                int cur = 0;
                                for(it_set = (*it_map)->Overlap.begin(); it_set != (*it_map)->Overlap.end(); it_set++){
                                        for(j = cur; j < *it_set; j++)
                                                model.add(yijk[i * tot_DFF_num + (*it_map)->DFF_id][j] == 0);
                                        model.add(yijk[i * tot_DFF_num + (*it_map)->DFF_id][*it_set] <= Xi[(*it_map)->DFF_id]);
                                        cur = *it_set + 1;
                                }
                        
                                for(j = cur; j < tot_DFF_num; j++)
                                        model.add(yijk[i * tot_DFF_num + (*it_map)->DFF_id][j] == 0);
                                
                                (*it_map)->R0_seq.clear();
                                (*it_map)->R1_seq.clear();
                        }

                        //constraint 2, Zj<=sum(yij)
                        IloExpr L1(env);
                        for(it_M = myMap1.begin(); it_M != myMap1.end(); it_M++){
                                for(it_set = (*it_M).second.begin(); it_set != (*it_M).second.end(); it_set++)
                                        L1 += yijk[i * tot_DFF_num + *it_set][(*it_M).first];
                                model.add(Zjk[(*it_M).first] <= L1);
                        }
                        L1.end();
                }
                
                
                //constraint 3, sum(Xi) = B
                IloExpr L0(env);
                for(i = 0; i < tot_DFF_num; i++)
                        L0 += Xi[i];
                model.add(L0 <= trace_size);
                
                
                //add objective expression
                IloExpr Visibility(env);
                for(i = 0; i < mode_num; i++)
                        for(j = 0; j < tot_DFF_num; j++)
                                Visibility += Zjk[i * tot_DFF_num + j];
                
                
                IloObjective obj = IloMaximize(env,Visibility);
                model.add(obj);
                L0.end();
                Visibility.end();
                
                //----------------------------------------------------solve and optimize-----------------------------------------------------
                IloCplex cp(model);
                cp.setParam(cp.EpGap,0.10);
                //cp.setParam(cp.TiLim,240);
                cp.setParam(cp.TreLim,6e9);
                cp.setParam(cp.MemoryEmphasis,true);
                cp.extract(model);
                cp.solve();
                
                //ofstream logfile("my.log");
                //cp.setOut(logfile);		  
                
                //----------------------------------------------------print out solution-----------------------------------------------------
                cout << std::endl << "Best Optimal value: " << cp.getBestObjValue() << std::endl;		    
                cout << std::endl << "Optimal value: " << cp.getValue(obj) << std::endl;
                cout << cp.getStatus() << std::endl;
                
                cout<<"Selected DFFs are "<<endl;
                for (i = 0; i < tot_DFF_num; i++){
                        if(cp.getValue(Xi[i]) == 1){
                                //cout << i << endl;
                                selected_traces.push_back(i);
                        }
                }
                
                cout << "selected trace number is " << selected_traces.size() << endl;
                cp.end();
                model.end();
        }
        catch (IloException& ex) {
                env.out() << "Error: " << ex << std::endl;
        }
        
        env.end();        
}



